﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.IO;
using System.Windows.Documents;
using System.Windows;

namespace FamilyShowSource.Models
{
    /// <summary>
    /// Presents a Story associated with a Person class
    /// </summary>
    public class Story : INotifyPropertyChanged
    {
        #region Fields

        /// <summary>
        /// The relative path to the story file.
        /// It is built from the Stories folder name and the stored file name 
        /// </summary>
        private string relativePath;

        /// <summary>
        /// Event raised when a property is changed on a component.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// The constants specific to this class
        /// </summary>
        public static class Const
        {
            /// <summary>
            /// Name of the folder which contains stories
            /// </summary>
            public const string StoriesFolderName = "Stories";
        }

        #endregion

        #region Properties

        /// <summary>
        /// The relative path to the story file.
        /// </summary>
        public string RelativePath
        {
            get { return this.relativePath; }
            set
            {
                if (this.relativePath != value)
                {
                    this.relativePath = value;
                    this.OnPropertyChanged("RelativePath");
                }
            }
        }

        /// <summary>
        /// The fully qualified path to the story.
        /// </summary>
        public string AbsolutePath
        {
            get
            {
                string tempFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 
                    App.ApplicationFolderName);
                tempFolder = Path.Combine(tempFolder, App.AppDataFolderName);

                if (this.relativePath != null)
                    return Path.Combine(tempFolder, relativePath);
                else
                    return string.Empty;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Empty constructor is needed for serialization
        /// </summary>
        public Story() { }

        #endregion

        #region Methods

        /// <summary>
        /// Save the story to the file system.
        /// </summary>
        /// <param name="storyText"></param>
        /// <param name="storyFileName"></param>
        public void Save(TextRange storyText, string storyFileName)
        {
            // Data format for the story file.
            string dataFormat = DataFormats.Rtf;

            string tempFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                App.ApplicationFolderName);
            tempFolder = Path.Combine(tempFolder, App.AppDataFolderName);

            // Absolute path to the stories folder
            string storiesLocation = Path.Combine(tempFolder, Const.StoriesFolderName);

            // Fully qualified path to the new story file
            storyFileName = this.GetSafeFileName(storyFileName);
            string storyAbsolutePath = Path.Combine(storiesLocation, storyFileName);

            try
            {
                // Create the stories directory if it doesn't exist
                if (Directory.Exists(storiesLocation) == false)
                    Directory.CreateDirectory(storiesLocation);

                // Open the file for writing the richtext
                using (FileStream stream = File.Create(storyAbsolutePath))
                {
                    // Store the relative path to the story
                    this.relativePath = Path.Combine(Const.StoriesFolderName, storyFileName);

                    // Save the story to disk
                    if (storyText.CanSave(dataFormat))
                        storyText.Save(stream, dataFormat);
                }
            }
            catch
            {
                // Could not save the story. Handle all exceptions
                // the same, ignore and continue.
            }
        }

        /// <summary>
        /// Return a string that is a safe file name.
        /// </summary>
        private string GetSafeFileName(string fileName)
        {
            // List of invalid characters.
            char[] invalid = Path.GetInvalidFileNameChars();

            // Remove all invalid characters.
            int pos;
            while ((pos = fileName.IndexOfAny(invalid)) != -1)
                fileName = fileName.Remove(pos, 1);

            return fileName;
        }

        /// <summary>
        /// Load the story from file to the TextRange
        /// </summary>
        /// <param name="storyText"></param>
        public void Load(TextRange storyText)
        {
            // Data format for the person's story file.
            string dataFormat = DataFormats.Rtf;

            if (File.Exists(this.AbsolutePath))
            {
                try
                {
                    // Open the file for reading
                    using (FileStream stream = File.OpenRead(this.AbsolutePath))
                    {
                        if (storyText.CanLoad(dataFormat))
                            storyText.Load(stream, dataFormat);
                    }
                }
                catch
                {
                    // Could not load the story. Handle all exceptions
                    // the same, ignore and continue.
                }
            }
        }

        /// <summary>
        /// Delete the person's story if it exists
        /// </summary>
        public void Delete()
        {
            if (File.Exists(this.AbsolutePath))
            {
                try
                {
                    File.Delete(this.AbsolutePath);
                }
                catch
                {
                    // Could not delete the file. Handle all exceptions
                    // the same, ignore and continue.
                }
            }
        }

        /// <summary>
        /// Raised event when the propety has changed on a component
        /// </summary>
        /// <param name="propertyName"></param>
        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
